package com.kira.solo.schedule.domain

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import com.kira.solo.schedule.pojo.CasePeriodTaskInfo
import com.kira.solo.schedule.pojo.PeriodType
import com.kira.solo.schedule.receiver.AlarmReceiver
import com.kira.solo.schedule.receiver.BootReceiver
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import java.util.Calendar
import javax.inject.Inject
import javax.inject.Singleton

/**
 *
 * @packageName com.kira.solo.schedule.utils
 * @date 2024/1/25 16:47
 * @author zhanglei
 */
@Singleton
class AlarmScheduleService @Inject constructor(@ApplicationContext private val context: Context) {
    private val alarms = MutableStateFlow(emptyMap<Long, PendingIntent>())
    private val alarmMgr by lazy { context.getSystemService(Context.ALARM_SERVICE) as AlarmManager }

    /**
     * 启动定时器
     */
    fun startAlarm(tasks: List<CasePeriodTaskInfo>) {
        // 取消
        cancelAllAlarms()
        tasks.forEach { task ->
            when (task.periodType) {
                is PeriodType.Custom -> customAlarm(task)
                PeriodType.EveryDay -> everyDayAlarm(task)
                PeriodType.Once -> onceAlarm(task)
                PeriodType.WorkDay -> workDayAlarm(task)
            }
        }
    }

    /**
     * 单次触发
     */
    private fun onceAlarm(casePeriodTaskInfo: CasePeriodTaskInfo) {
        val alarmIntent = casePeriodTaskInfo.taskId.pendingIntent()

        // Set the alarm to start at 8:30 a.m.
        val calendar: Calendar = Calendar.getInstance().apply {
            timeInMillis = System.currentTimeMillis()
            set(Calendar.HOUR_OF_DAY, casePeriodTaskInfo.time.hour)
            set(Calendar.MINUTE, casePeriodTaskInfo.time.minute)
        }
        if (calendar.timeInMillis < System.currentTimeMillis()) return
        alarmMgr.setExact(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            alarmIntent
        )
        alarmIntent.cache(casePeriodTaskInfo.taskId)
    }

    /**
     * 每日触发
     */
    private fun everyDayAlarm(casePeriodTaskInfo: CasePeriodTaskInfo) {
        val alarmIntent = casePeriodTaskInfo.taskId.pendingIntent()
        // Set the alarm to start at 8:30 a.m.
        val calendar: Calendar = Calendar.getInstance().apply {
            timeInMillis = System.currentTimeMillis()
            set(Calendar.HOUR_OF_DAY, casePeriodTaskInfo.time.hour)
            set(Calendar.MINUTE, casePeriodTaskInfo.time.minute)
        }
        alarmMgr.setInexactRepeating(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            AlarmManager.INTERVAL_DAY,
            alarmIntent
        )
        alarmIntent.cache(casePeriodTaskInfo.taskId)
    }

    /**
     * 工作日触发
     */
    private fun workDayAlarm(casePeriodTaskInfo: CasePeriodTaskInfo) {
        val alarmIntent = casePeriodTaskInfo.taskId.pendingIntent()
        // Set the alarm to start at 8:30 a.m.
        val calendar: Calendar = Calendar.getInstance().apply {
            timeInMillis = System.currentTimeMillis()
            set(Calendar.HOUR_OF_DAY, casePeriodTaskInfo.time.hour)
            set(Calendar.MINUTE, casePeriodTaskInfo.time.minute)
        }
        alarmMgr.setInexactRepeating(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            AlarmManager.INTERVAL_DAY,
            alarmIntent
        )
        alarmIntent.cache(casePeriodTaskInfo.taskId)
    }

    /**
     * 自定义日期触发
     */
    private fun customAlarm(casePeriodTaskInfo: CasePeriodTaskInfo) {
        val alarmIntent = casePeriodTaskInfo.taskId.pendingIntent()
        // Set the alarm to start at 8:30 a.m.
        val calendar: Calendar = Calendar.getInstance().apply {
            timeInMillis = System.currentTimeMillis()
            set(Calendar.HOUR_OF_DAY, casePeriodTaskInfo.time.hour)
            set(Calendar.MINUTE, casePeriodTaskInfo.time.minute)
        }
        alarmMgr.setInexactRepeating(
            AlarmManager.RTC_WAKEUP,
            calendar.timeInMillis,
            AlarmManager.INTERVAL_DAY,
            alarmIntent
        )
        alarmIntent.cache(casePeriodTaskInfo.taskId)
    }

    /**
     * 取消所有定时
     */
    private fun cancelAllAlarms() {
        alarms.update {
            it.values.forEach { pendingIntent ->
                alarmMgr.cancel(pendingIntent)
            }
            emptyMap()
        }
    }

    /**
     * enable 接收重启事件
     */
    private fun enableBootReceiver() {
        val receiver = ComponentName(context, BootReceiver::class.java)

        context.packageManager.setComponentEnabledSetting(
            receiver,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
        )
    }

    private fun PendingIntent.cache(id: Long) {
        alarms.update { it + (id to this) }
    }

    private fun Long.pendingIntent(flags: Int = 0): PendingIntent {
        return Intent(context, AlarmReceiver::class.java).let { intent ->
            intent.putExtra("taskId", this)
            PendingIntent.getBroadcast(context, 0, intent, flags)
        }
    }
}